home *** CD-ROM | disk | FTP | other *** search
- goto example1
- ' The QuickBASIC Tutorial Series
-
- ' Part 4
- ' File Input/Output
-
- ' Copyright 1986 Ford Software
-
- ' 4845 Willowbend Blvd.
- ' Houston, TX 77035
- ' (713) 721-5205
- ' CompuServe ppn: 71355,470
-
- 'This Tutorial may not be copied or distributed in any form - printed, on disk
- 'or electronically - without the express written permission of Ford Software.
- ' Unlicensed distribution is a violation of copyright law
- ' and may be subject to civil and criminal prosecution.
-
- 'QuickBASIC is a trademark of the Microsoft Corporation.
- 'Ford Software is not associated in any way with the Microsoft Corporation.
-
- '(Make sure NumLock is off and press PgDn)
- 'page 2 I N T R O D U C T I O N
-
- 'I can remember file input/output programming being the most difficult part
- 'of BASIC programming to grasp for reasons I can no longer remember. One
- 'reason may have been that I was trying to learn it from an operating system
- 'reference manual (Radio Shack's TRS-DOS manual), instead of from a tutorial.
-
- 'Hopefully, we can approach the subject in a way that will make things easier
- 'to understand. Remember to keep the QB2 manual open to the subject we are
- 'discussing for help with topics we may not cover in enough detail for you.
-
- 'Also remember how to run examples of code: press Ctrl-PgUp to get to the
- 'start of this file. Change that first line to read "goto example#" for the
- 'example number you want to run. Return to the page you were on and press
- 'Ctrl-R to compile and run the example.
-
- 'DEFINITIONS: A "field" is a single item of information, such as "Address".
- ' A "record" is a set of fields, such as:
- ' First Name, Last Name, Address, City, State, Zip, Telephone #
-
-
- '(Press PgDn)
- 'page 3
- ' Contents
-
- ' page
-
- ' 4 The FILES Command
- ' 5 Types of Files
- ' 6 OPEN - Sequential
- ' 7 Writing to a Sequential File
- ' 11 Random Access Files
- ' 12 The FIELD and GET Statements
- ' 14 LSET / RSET
- ' 15 More about FIELDing
- ' 17 Opening Non-Data Files
- ' 18 Compressing Numbers
- ' 19 EOF, LOF and LOC
-
-
- ' To search for specific text, use Ctrl-F.
-
-
- '(Press PgDn)
- 'page 4 The FILES Command
-
- 'The FILES Command is similar to DOS's DIR command with the /W (wide display)
- 'option specified. That is, FILES shows the files in four columns and without
- 'showing the file time, date or size.
- example1:
- FILES
- INPUT "Ready for FILES *.BAS"; X$
- FILES "*.bas"
- INPUT "Ready for FILES TUTOR-??.*"; X$
- FILES "TUTOR-??.*"
- INPUT "Ready to see FILES use a variable"; X$
- Y$="tutor-"
- FILES Y$+"*.BAS"
- INPUT "Ready for a FILES error message"; X$
- FILES Y$+"??" 'After getting the runtime error message and returning to
- END 'this screen, press Alt-V, E, Enter to remove the Error box.
- 'As you can see, if the specified file is not found, the program aborts all
- 'the way back to DOS. In a later lesson, we will see how to get around this
- 'problem so that your program can continue running if a file isn't found.
-
- ' (PgDn)
- 'page 5 Types of Files
-
- 'Generally speaking, there are two broad types of files, program files and
- 'data files. Either type of file can be modified from within BASIC. For
- 'example, if you have written a program and compiled it into an "EXE" file,
- 'you could open the "EXE" file as if it were a data file and imbed a serial
- 'number or your customer's name in it without having to change it in the
- 'source code and recompiling it.
-
- 'There are four things you can do with a file: open the file, write data to
- 'the file, read data from the file, and close the file. When you write to or
- 'read from the file, the computer does not physically go to the disk each
- 'time. Instead, the computer uses some memory to store the data until it gets
- 'to be enough to make the trip worthwhile or until the file is going to be
- 'closed or some other factor causes the data to be written. This area of
- 'memory is called a "buffer". If you have three files open at the same time,
- 'each one must have its own buffer area. Read in your DOS manual about setting
- 'up file buffer areas in your CONFIG.SYS file.
-
- 'There are two ways to access files, sequentially or randomly. We tend to
-
- ' (PgDn)
- 'page 5b (Types of Files)
-
- 'think of a file as being "sequential" or "random", depending on certain
- 'characteristics, but any file can be opened for either access method, no
- 'matter how the file was originally opened and written to. If we sometimes
- 'refer to a "random access file" or a "sequential file", we are referring to
- 'the way it is normally opened, written to, and read from.
-
- 'In addition, in normal usage, the two different types of files will have
- 'specific characteristics that will distinguish them.
-
- 'Sequential files can have records of varying lengths because a record is
- 'defined as a series of characters ending with a carriage return and linefeed.
- 'The fields within a record are seperated by "delimiters" (commas, quotes).
-
- 'Random access files normally have records of the same length. This makes it
- 'easy for the system to find any record by multiplying the record number times
- 'the record length. Fields in a record are also defined by length, so delimit-
- 'ers are not required. We will now look at these two types of files in detail.
-
-
- ' (PgDn)
- 'page 6 OPEN - Sequential
-
- 'Sequential files must be opened for reading or writing only and can only be
- 'read from or written to in sequential order. An important point is that when
- 'you open a file for sequential output, if a file with that name already
- 'exists, it is erased. It is up to you to make sure that an existing file is
- 'not erased in this manner. An exception is that you can open a file to append
- 'data to the end of the file. Here are some example of sequential OPENs. Be
- 'sure to read the OPEN Statement in the QB2 manual.
-
- example2:
- filename$="test1"
- buffernum=1
- OPEN filename$ FOR OUTPUT AS buffernum 'open a file for sequential writing.
- CLOSE
- OPEN filename$ FOR INPUT AS buffernum 'open a file for sequential input.
- OPEN "test2" FOR OUTPUT AS 2 'open a second file for output.
- CLOSE 2 'close only the second file.
- OPEN filename$ FOR APPEND AS buffernum 'open a file to add data to the end.
- CLOSE 'closes both files 1 and 2.
-
- ' (PgDn)
- 'page 7 Writing to a Sequential File
-
- 'There are two commands for writing to a sequential file: PRINT # and WRITE #.
- 'The PRINT #n command is very similar to the PRINT command that writes data to
- 'the screen, even to the extent of having a "PRINT #n USING" option to format
- 'data into the file like PRINT USING does to the screen. In fact, this may be
- 'a good time to point out that the screen can be OPENed as an output device
- 'and written to sequentially just like a disk file.
-
- 'To understand the finer points of PRINTing data to a file, you need to first
- 'understand how QB2 reads data in from a sequential file using INPUT #. Again,
- 'the INPUT #n command is similar to the INPUT command used to get input from
- 'the user. This means that commas and quote marks are used to seperate data
- 'items in the input field. To review how INPUT from the keyboard works, say
- 'you have a line like:
- ' INPUT "Enter name, age, weight, address: ", N$, A, W, A$
- 'If the user enters: Bill Will, 30, 150, 1234 Elm Street
- 'everything is fine. The four fields are "delimited" by commas.
- 'If he enters: Bill Will, 30, 150, Houston, TX there is a problem because
- 'it looks like five data items to INPUT, so the user must put the address in
- 'quotes: Bill Will, 30, 150, "Houston, TX"
- ' (PgDn)
- 'page 8 (Writing to a sequential file, cont.)
-
- 'If you start text with a double quote mark ("), everything that follows up to
- 'the next double quote mark is assigned to one variable. For example, if you
- 'enter: "Big D" Dallas, 30 in response to INPUT "Address, age"; A$, A
- 'the computer will see this as three variables. You can, however, have quotes
- 'within a response. For example: New "The Big Apple" York, 20
- 'Run the following example and try different responses with commas and quotes
- 'to get a feel for how they are treated. Enter quit, 0, 0, x to end.
- example3:
- WHILE N$<>"quit"
- INPUT "Enter name, age, weight, address: ", N$, A, W, A$
- PRINT N$, A, W, A$
- WEND : END
-
- 'Now, knowing that INPUT will want to see Bill Will, 30, 150, "Houston, TX"
- 'in the file with the quote marks as shown, how do you put the quote marks
- 'into the file? If you say PRINT "Houston, TX", 40 you know the quotes
- 'will not appear on the screen. Neither will they appear in the file. You must
- 'enter the ASCII code for the quote mark, which is CHR$(34):
- ' PRINT #1, "Bill Will", 30, 150, CHR$(34) "Houston, TX" CHR$(34)
- ' (PgDn)
- 'page 9 (Writing to a sequential file, cont.)
-
- 'The other problem is that the comma will not appear in the file either, so
- 'the PRINT line just shown is not correct either. However, while you can't put
- 'a quote mark between quotes ("""), you can put a comma between quotes (",").
- example4:
- OPEN "test4" FOR OUTPUT AS #1
- PRINT #1, "Bill Will," 30 "," 150 ",Houston, TX"
- PRINT #1, "Bill Will," 30 "," 150 "," CHR$(34) "Houston, TX" CHR$(34)
- CLOSE
- OPEN "test4" FOR INPUT AS #1
- PRINT "This is how the data actually looks in the file:"
- LINE INPUT #1, A$ : LINE INPUT #1, B$
- PRINT A$ : PRINT B$ : PRINT
- CLOSE
- OPEN "test4" FOR INPUT AS #1
- PRINT "This is how the data gets loaded into the variables N$, A, W, A$:"
- INPUT #1, N$, A, W, A$ : PRINT N$, A, W, A$ : INPUT #1, missed.field$
- INPUT #1, N$, A, W, A$ : PRINT N$, A, W, A$
- PRINT "Notice that 'TX' didn't get into the variable A$ in the first line"
- PRINT "because the comma says that TX is a seperate variable.": CLOSE: end
- ' (PgDn)
- 'page 10 (Writing to a sequential file, cont.)
-
- 'There is an easy way to write data to a sequential file without having to
- 'worry about commas and quotes. Use the WRITE command, which automatically
- 'delimits variables with commas and quotes.
- example5:
- OPEN "test5" FOR OUTPUT AS #1
- PRINT #1, "Bill Will", 30, 150, "Houston, TX"
- WRITE #1, "Bill Will", 30, 150, "Houston, TX"
- CLOSE : OPEN "test5" FOR INPUT AS #1
- PRINT "This is how the data actually looks in the file:"
- LINE INPUT #1, A$: PRINT A$ : LINE INPUT #1, A$: PRINT A$
- CLOSE: OPEN "test5" FOR INPUT AS #1
- PRINT "We saw in Example4 that the first line will not load back correctly:"
- INPUT #1, N$, A$: PRINT "N$ = "N$: PRINT "A = "A: PRINT "W =": PRINT "A$ ="
- PRINT "All data up to the first comma was assigned to the first varible."
- PRINT "So 'TX' is read into the variable 'A'."
- PRINT "The next line, stored with the WRITE statement, is properly delimited:"
- INPUT #1, N$, A, W, A$
- PRINT "N$ = "N$ : PRINT "A = " A : PRINT "W = " W : PRINT "A$ = " A$
- CLOSE: end
- ' (PgDn)
- 'page 11 Random Access Files
-
- 'As we have said, any file can be opened for random access. However, in order
- 'to make sense of the data, it needs to be arranged into fixed-length fields
- 'in fixed-length records. The reason why is that when you open a file for
- 'random access, you define how many characters are read into a particular
- 'variable, unlike sequential files that rely on commas, quotes and carriage
- 'returns to determine what data goes into a particular variable.
-
- 'Examples of records in a variable-record-length (sequential) file:
- 'Bill Will, 30, 150, "Houston, TX"
- 'Roger Bovine, 22, 180, "Summerfield, LA"
-
- 'Example of records in a fixed-record-length (random access) file:
- 'Bill Will 30150Houston, TX Roger Bovine 22180Su
- 'mmerfield, LA
-
- 'In the fixed-record-length file, not only are delimiters not requred, you
- 'need not even leave spaces between the fields. You will also notice that
- 'there is no carriage return/line feed between records, so if you TYPE the
- 'file in DOS, you will see the records running together.
- ' (PgDn)
- 'page 12 The FIELD & GET Statements
-
- 'You get the data in a random access file into the proper variables by using
- 'the FIELD statement. Using the data from the preceeding page as an example:
- 'OPEN "DATAFILE" AS #1 LEN=45 'each record is 45 characters long
- 'FIELD #1, 25 AS NAM$, 2 AS AGE$, 3 AS WT$, 15 AS ADDR$
-
- 'You can now retrieve any record in the file with the GET command. GET #1, 7
- 'retrieves the second record. It's location in the file is easily calculated
- 'by the system: LOC=REC.LEN*(REC.NUM-1)+1. In this case: 45*(7-1)+1=271, so
- 'the seventh record starts at the 271st character in the file.
-
- 'If you count the characters in the data on the preceeding page, you will see
- 'that the data in the two run-on records fit the above FIELD statment. Blanks
- 'between fields become part of the variable. For example, if you say GET 1,1
- 'to retrieve the first record, the variable NAM$ will contain 25 characters,
- 'consisting of the name Bill Will and 16 blank spaces.
-
- 'All fielded variables must be strings, so AGE$ would be "30". To convert it
- 'to a numeric variable, you would have to say AGE%=VAL(AGE$).
-
- ' (PgDn)
- 'page 13 The LSET Command
-
- 'In the previous example, the first name and last name were lumped into one
- 'variable, as were city and state, just to maintain continuity with examples
- 'of sequential files. Normally, first and last names in a random file would
- 'be seperated, as would city and state. Here is a more realistic example:
- example6:
- OPEN "test6" AS #1 LEN=45 'open a file for random I/O (Input/Output)
- FIELD #1, 10 AS FIRST.NAME$, 15 AS LAST.NAME$, 2 AS AGE$, 3 AS WT$,_
- 13 AS CITY$, 2 AS STATE$ 'define the fields
- LSET FIRST.NAME$="Roger": LSET LAST.NAME$="Bovine": LSET AGE$="22"
- LSET WT$="180": LSET CITY$="Summerfield": LSET STATE$="LA"
- PUT #1, 2 'just for grins, save the second record first
- LSET FIRST.NAME$="Bill": LSET LAST.NAME$="Will": LSET AGE$="30"
- LSET WT$="150": LSET CITY$="Houston": LSET STATE$="TX"
- PUT #1, 1 'save the first record
- GET #1, 2 'get the second record and print it
- PRINT FIRST.NAME$ " " LAST.NAME$ " " AGE$ " " WT$ " " CITY$ ", " STATE$
- FIELD #1, 45 AS WHOLE.REC$ : PRINT WHOLE.REC$ : CLOSE #1 : END
- ' (The next several pages will discuss the code above. Continue reading.)
-
- ' (PgDn)
- 'page 14 LSET / RSET
-
- 'The LSET and RSET commands are used to assign data to a FIELDed variable.
- 'Most of the time you will use LSET, which left-justifies the data in the
- 'field and pads the rest of the field with blands. RSET right-justifies the
- 'data in the field and pads the beginning of the field with blanks.
-
- '=============================== W A R N I N G ===============================
- ' The single most common mistake in dealing with FIELDed variables is to
- ' assign data to a FIELDed variable without using LSET or RSET. BASIC does
- ' not consider this an error and will change the value of the variable,
- ' but any GET's that follow WILL NOT CHANGE THE VALUE OF THE VARIABLE:
- example7: '(The file from example6 should already be on your disk.)
- OPEN "test6" AS #1 LEN=45
- FIELD #1, 10 AS FIRST.NAME$, 15 AS LAST.NAME$
- GET 1,1 : PRINT FIRST.NAME$ " " LAST.NAME$
- FIRST.NAME$="we goofed" 'no LSET/RSET used; GET won't work right now.
- GET 1,1 : PRINT FIRST.NAME$ " " LAST.NAME$
- PRINT "So let's FIELD it again:" : FIELD 1, 10 AS FIRST.NAME$
- LSET FIRST.NAME$="we done good this time" 'GET will replace this data.
- GET 1,1 : PRINT FIRST.NAME$ " " LAST.NAME$ : CLOSE : END
- ' (PgDn)
- 'page 15 More About FIELDing
-
- 'You can have several FIELD statements in affect at once. In fact, if you have
- 'done a GET and then do a FIELD, as above, the data that you have already
- 'retrieved will be assigned to the newly FIELDed variables without having to
- 'do a GET again, as shown by running example 6.
-
- 'While it is obviously much easier to assign an entire record to one variable,
- 'it is easier to work with the data in the record by assigning each field to a
- 'seperate variable, so you often want to FIELD both types of variables:
- 'FIELD 1, 25 AS NAM$ : PRINT NAM$
- 'FIELD 1, 10 AS FIRST.NAME$, 15 AS LAST.NAME$
- 'PRINT LAST.NAME$ "," FIRST.NAME$
-
- 'As shown in example 7, you don't have to FIELD an entire record if you are
- 'not interested in all of the data. If the fields you are interested in are
- 'not the first ones in the record, you can assign data to dummy variables:
- 'FIELD 1, 10 AS X$, 15 AS X$, 2 AS AGE$ or
- 'FIELD 1, 25 AS X$, 2 AS AGE$
- 'Notice that you can safely assign several fields to the same dummy variable.
-
- ' (PgDn)
- 'page 16 (More About FIELDing, cont.)
-
- 'You can use loops, data statements and dummy variables to more easily FIELD
- 'long or complex records:
- 'X=0
- 'FOR I=1 TO 6
- ' READ FLD.LEN : FIELD 1, X AS X$, FLD.LEN AS FLD$(I) : X=X+FLD.LEN
- 'NEXT
- 'DATA 10, 15, 2, 3, 13, 2
- ' While it is helpful to have meaningful filenames, such as AGE$, it is
- 'sometimes advantageous to have subscripted FIELDed variables. For example,
- 'FOR I=1 TO 6 : LSET FLD$(I) = "" : NEXT clears out all the variables much
- 'more easily than having to name each of the six variables individually.
-
- 'In the example above, X is used to keep track of how much of the record has
- 'already been fielded, which, the first time through is zero. The second time
- 'through X=10, so the first 10 characters, which have already been assigned to
- 'FLD$(1), are assigned to a dummy variable and FLD.LEN, which is now 15, is
- 'assigned to FLD$(2). Since we don't have to FIELD the entire record, we can
- 'leave the rest of the record unfielded until the FIELDing loop gets to it
- 'by way of X being incremented each time.
- ' (PgDn)
- 'page 17 Opening Non-Data Files
-
- 'We've said that any file - even a program file - can be opened, read from and
- 'written to, and that any file can be read from or written to sequentially or
- 'as random access. To illustrate, we will now open and read from this program
- 'file itself. Notice that with the sequential read, we have to step through
- 'each "record" (in this case, a "record" is each line that ends with a
- 'carriage return and line feed), while with random access, we will jump
- 'directly to the "records" that contain the text of this page.
- example8:
- OPEN "TUTOR-04.BAS" FOR INPUT AS 1
- FOR I=1 TO 352: LINE INPUT #1, A$: PRINT I: NEXT
- FOR I=1 TO 22: LINE INPUT #1, A$: PRINT A$: NEXT : PRINT
- INPUT "NOW RANDOM ACCESS"; X$: CLOSE: PRINT
- OPEN "TUTOR-04.BAS" AS 1 LEN=1
- FIELD 1, 1 AS A$
- FOR I=17381 TO 18325
- GET 1,I
- IF ASC(A$)<>10 THEN PRINT A$; 'filter out the extra linefeed
- NEXT : CLOSE : PRINT : END
-
- ' (PgDn)
- 'page 18 Compressing Numbers
-
- 'You may have noticed that only string data can be assigned to a FIELDed
- 'variable. That means that a number must be converted to a string before
- 'or during assigment: LSET AGE$=STR$(AGE%).
-
- 'In order to both save space and make it easier to maintain standard record
- 'length in random access files, numbers can be converted to a special compres-
- 'sed, fixed-length string data. (See MKI$, MKS$, and MKD$ in the manual.)
-
- 'MKI$ converts an integer to a two-byte string; MKS$, a single-precision num-
- 'ber to a four-byte string; and MKD$, a double-precision number to an eight-
- 'byte string. The characters used in this string include any of the 255 ASCII
- 'characters, some of which look funny or are not printable at all when you
- 'try to view them on the screen:
- example9:
- N$=MKI$(1449) : PRINT "MKI$(1449) = " N$ : PRINT "LEN(N$) =" LEN(N$)
- PRINT "Converts back to" CVI(N$) 'CVI, CVS and CVD convert the strings back.
- N$=MKS$(12345+54321) : PRINT "MKS$(12345+54321) =" N$
- PRINT "LEN(N$) =" LEN(N$)
- PRINT "Converts back to" CVS(N$) : END
- ' (PgDn)
- 'page 19 EOF, LOF and LOC
-
- 'EOF is used to test for the last record of a file so that you do not attempt
- 'to read beyond the end of a file. eg: WHILE NOT EOF(1): GET 1: WEND
-
- 'LOF lets you calculate the number of records in a random access file. To do
- 'this, divide the value of LOF by the defined record length of the file. eg:
- 'OPEN "DATAFILE" AS 1 LEN=125 : NUM.RECS = LOF(1) / 125
- 'FOR I=1 TO NUM.RECS : GET 1 : NEXT
-
- 'LOC tells you where you are in a datafile, primarily used for random access
- 'files. eg: GET 1, 37 : PRINT LOC(1) will print the number 37, since that is
- 'the number of the last record read or written. LOC is more useful if you
- 'don't know where in the file you are, which can happen if you do a series
- 'of GETs without record numbers (which causes the system to just get the
- 'next record in the file). For example:
- 'OPEN "MY-FILE.DTA" AS 1 LEN=55: FIELD 1, 25 AS NAM$, 5 AS ID$, 25 AS ADDR$
- 'WHILE ID$ <> "A1032" : GET 1 : WEND 'searches the file for ID# A1032
- 'LSET ID$="Z1032" 'changes the ID# to Z1032
- 'PUT 1, LOC(1) 'Just saying "PUT 1" would replace the data in the NEXT record
- ' instead of the one just read.
- '(end of lesson 4)
-
-
-
-
- (end of file - press PgUp)
-